/**
 * Copyright 2014-2020 the original author or authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.upb.webserver.security.customizeAuth;

import com.upb.webserver.account.AccountService;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.pojo.account.AccountCommon;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.dao.mapper.TbTokenMapper;
import com.upb.webserver.token.TokenService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import javax.xml.ws.WebServiceException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

@Log4j2
public class TokenAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private AccountService accountService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private TbTokenMapper tokenMapper;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String token = authentication.getName();
        log.info("start exec method [authenticate], token:{}", token);

        AbstractAuthenticationToken result;
        try {
            result = buildAuthentication(tokenService.getValueFromToken(token));
            tokenService.updateExpireTime(token);
            tokenMapper.removeExpireToken();
        } catch (WebServerException wex){
            log.warn("fail exec method [authenticate] with WebServerException", wex);
            throw new CredentialsExpiredException(JsonUtils.objToString(wex.getRetCode()));
        }catch (Exception ex) {
            log.warn("fail exec method [authenticate]", ex);
            throw new CredentialsExpiredException(JsonUtils.objToString(ConstantCode.TOKEN_EXPIRE)); //catch by AbstractAuthenticationFilter.doFilterInternal
        }
        result.setDetails(authentication.getDetails());
        return result;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return TokenAuthenticationToken.class.isAssignableFrom(authentication);
    }

    /**
     * @param accountJsonBase64
     * @return
     */
    private AbstractAuthenticationToken buildAuthentication(String accountJsonBase64) {
        AccountCommon account = accountService.getAccountCommon(accountJsonBase64);
        return new TokenAuthenticationToken(accountJsonBase64, buildAuthorities(account.getRoleName()));
    }

    /**
     * @param roleName
     * @return
     */
    private Collection<SimpleGrantedAuthority> buildAuthorities(String roleName) {
        final Collection<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
        List<String> authorities = Arrays.asList("ROLE_" + roleName);
        for (String authority : authorities) {
            simpleGrantedAuthorities.add(new SimpleGrantedAuthority(authority));
        }
        return simpleGrantedAuthorities;
    }
}